﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Dynamic;
using Eisk.BusinessEntities;
using Eisk.DataAccessLayer;
namespace Eisk.BusinessLogicLayer
{
    [System.ComponentModel.DataObject(true)]
    public partial class EmployeeBLL : IDisposable
    {
        #region Constructors, Dependency and Partial Method Declaration

        public EmployeeBLL() : this(new DatabaseContext()) { }

        public EmployeeBLL(DatabaseContext DatabaseContext)
        {
            _DatabaseContext = DatabaseContext;
        }

        DatabaseContext _DatabaseContext;

        public void Dispose()
        {
            if (_DatabaseContext != null)
            {
                _DatabaseContext.Dispose();
                _DatabaseContext = null;
            }
            
            GC.SuppressFinalize(this);
        }

        partial void OnEmployeeSaving(Employee employee);

        partial void OnEmployeeCreating(Employee employee);
        partial void OnEmployeeCreated(Employee employee);

        partial void OnEmployeeUpdating(Employee employee);
        partial void OnEmployeeUpdated(Employee employee);

        partial void OnEmployeeSaved(Employee employee);

        partial void OnEmployeeDeleting(Employee employee);
        partial void OnEmployeeDeleted(Employee employee);


        #endregion

        #region Get Methods

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public Employee GetEmployeeByEmployeeId(int employeeId)
        {
            //Validate Input
            if (employeeId <= Employee.EmployeeIdMinValue)
                throw (new ArgumentOutOfRangeException("employeeId"));
            
            return (_DatabaseContext.Employees.FirstOrDefault(empObj => empObj.EmployeeId == employeeId));
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
        public List<Employee> GetEmployeesByReportsTo(int? reportsTo)
        {
            //Validate Input
            if (reportsTo == Employee.EmployeeIdMinValue)
                return GetAllEmployees();
            else if (reportsTo < Employee.EmployeeIdMinValue)
                throw (new ArgumentOutOfRangeException("reportsTo"));

            return (from employee in _DatabaseContext.Employees
                    where reportsTo == null ? employee.ReportsTo == null : employee.ReportsTo == reportsTo
                    select employee).ToList();
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
        public List<Employee> GetEmployeesByReportsToPaged(int? reportsTo, string orderBy, int startRowIndex, int maximumRows)
        {
            //Validate Input
            if (reportsTo == Employee.EmployeeIdMinValue)
                return GetAllEmployeesPaged(orderBy, startRowIndex, maximumRows);
            else if (reportsTo < Employee.EmployeeIdMinValue)
                throw (new ArgumentOutOfRangeException("reportsTo"));

            if (string.IsNullOrEmpty(orderBy))
                orderBy = "EmployeeId";
            
            return (
                    from employee in
                        _DatabaseContext.Employees
                        .DynamicOrderBy(orderBy)
                    where reportsTo == null ? employee.ReportsTo == null : employee.ReportsTo == reportsTo
                    select employee
                    )
                    .Skip(startRowIndex)
                    .Take(maximumRows)
                    .ToList();
        }

        public int GetTotalCountForAllEmployeesByReportsTo(int? reportsTo, string orderBy, int startRowIndex, int maximumRows)
        {
            //Validate Input
            if (reportsTo == Employee.EmployeeIdMinValue)
                return GetTotalCountForAllEmployees(orderBy, startRowIndex, maximumRows);
            else if (reportsTo < Employee.EmployeeIdMinValue)
                throw (new ArgumentOutOfRangeException("reportsTo"));

            return _DatabaseContext.Employees.Count(employee => reportsTo == null ? employee.ReportsTo == null : employee.ReportsTo == reportsTo);
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
        public List<Employee> GetAllEmployees()
        {
            return _DatabaseContext.Employees.ToList();
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
        public List<Employee> GetAllEmployeesPaged(string orderBy, int startRowIndex, int maximumRows)
        {
            if (string.IsNullOrEmpty(orderBy))
                orderBy = "EmployeeId";

            return (
                    from employee in 
                        _DatabaseContext.Employees
                        .DynamicOrderBy(orderBy)
                    select employee
                    )
                    .Skip(startRowIndex)
                    .Take(maximumRows)
                    .ToList();
        }

        public int GetTotalCountForAllEmployees(string orderBy, int startRowIndex, int maximumRows)
        {
            return _DatabaseContext.Employees.Count();
        }

        #endregion

        #region Persistence (Create, Update, Delete) Methods

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, true)]
        public int CreateNewEmployee(Employee newEmployee)
        {
            // Validate Parameters
            if (newEmployee == null)
                throw (new ArgumentNullException("newEmployee"));

            // Validate Primary key value
            if (newEmployee.EmployeeId > Employee.EmployeeIdMinValue)
                throw (new ArgumentOutOfRangeException("newEmployee"));

            // Apply business rules
            OnEmployeeSaving(newEmployee);
            OnEmployeeCreating(newEmployee);

            if (newEmployee.EntityState == EntityState.Detached)
                _DatabaseContext.Employees.Attach(newEmployee);
            _DatabaseContext.ObjectStateManager.ChangeObjectState(newEmployee, EntityState.Added);
            int numberOfAffectedRows = _DatabaseContext.SaveChanges();
            if (numberOfAffectedRows == 0) 
                throw new InvalidOperationException("No employee created!");

            // Apply business workflow
            OnEmployeeCreated(newEmployee);
            OnEmployeeSaved(newEmployee);

            return newEmployee.EmployeeId;
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]
        public void UpdateEmployee(Employee updatedEmployee)
        {
            // Validate Parameters
            if (updatedEmployee == null)
                throw (new ArgumentNullException("updatedEmployee"));

            // Validate Primary key value
            if (updatedEmployee.EmployeeId <= Employee.EmployeeIdMinValue)
                throw (new ArgumentOutOfRangeException("updatedEmployee"));

            // Apply business rules
            OnEmployeeSaving(updatedEmployee);
            OnEmployeeUpdating(updatedEmployee);

            //attaching and making ready for parsistance
            if (updatedEmployee.EntityState == EntityState.Detached)
                _DatabaseContext.Employees.Attach(updatedEmployee);
            _DatabaseContext.ObjectStateManager.ChangeObjectState(updatedEmployee, System.Data.EntityState.Modified);
            int numberOfAffectedRows = _DatabaseContext.SaveChanges();
            if (numberOfAffectedRows == 0) 
                throw new InvalidOperationException("No employee updated!");

            //Apply business workflow
            OnEmployeeUpdated(updatedEmployee);
            OnEmployeeSaved(updatedEmployee);

        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Delete, true)]
        public void DeleteEmployee(Employee employeeToBeDeleted)
        {
            //Validate Input
            if (employeeToBeDeleted == null)
                throw (new ArgumentNullException("employeeToBeDeleted"));

            // Validate Primary key value
            if (employeeToBeDeleted.EmployeeId <= Employee.EmployeeIdMinValue)
                throw (new ArgumentOutOfRangeException("employeeToBeDeleted"));

            OnEmployeeSaving(employeeToBeDeleted);
            OnEmployeeDeleting(employeeToBeDeleted);

            if (employeeToBeDeleted.EntityState == EntityState.Detached)
               _DatabaseContext.Employees.Attach(employeeToBeDeleted);
            _DatabaseContext.ObjectStateManager.ChangeObjectState(employeeToBeDeleted, System.Data.EntityState.Deleted);
            int numberOfAffectedRows = _DatabaseContext.SaveChanges();
            if (numberOfAffectedRows == 0) 
                throw new InvalidOperationException("No employee deleted!");
            
            OnEmployeeDeleted(employeeToBeDeleted);
            OnEmployeeSaved(employeeToBeDeleted);

        }

        public void DeleteEmployees(List<int> employeesIdsToDelete)
        {
            //Validate Input
            foreach (int employeeId in employeesIdsToDelete)
                if (employeeId <= Employee.EmployeeIdMinValue)
                    throw (new ArgumentOutOfRangeException("employeesIdsToDelete"));

            List<Employee> employeesToBeDeleted = new List<Employee>();

            foreach (int employeeId in employeesIdsToDelete)
            {
                Employee employee = new Employee { EmployeeId = employeeId };
                _DatabaseContext.Employees.Attach(employee);
                _DatabaseContext.ObjectStateManager.ChangeObjectState(employee, System.Data.EntityState.Deleted);
                employeesToBeDeleted.Add(employee);
                OnEmployeeDeleting(employee);
            }

            int numberOfAffectedRows = _DatabaseContext.SaveChanges();
            if (numberOfAffectedRows != employeesIdsToDelete.Count) 
                throw new InvalidOperationException("One or more employee records have not been deleted.");
            foreach (Employee employeeToBeDeleted in employeesToBeDeleted)
                OnEmployeeDeleted(employeeToBeDeleted);
        }

        #endregion

    }
}

